from django.shortcuts import render, reverse
from web.forms.issues import IssuesModelForm, IssuesReplyModelForm, InviteModelForm
from django.http import JsonResponse
from web import models
from utils.pagination import Pagination
from django.views.decorators.csrf import csrf_exempt
import json
from django.utils.safestring import mark_safe
from utils.encrypt import uid
import datetime


class CheckFilter(object):
    def __init__(self, name, data_list, request):
        self.name = name
        self.data_list = data_list
        self.request = request

    def __iter__(self):
        for item in self.data_list:
            key = str(item[0])
            text = str(item[1])
            ck = ""
            # 如果当前用户请求get请求l中status和当前循环key相等
            value_list = self.request.GET.getlist(self.name)
            # 判断当前id是否存在value_list(通过get请求获得,没有则空)里
            if key in value_list:
                ck = "checked"
                # 已经存在的值不需要在添加在url后面(因为不想让原本的值被覆盖)
                value_list.remove(key)
            else:
                value_list.append(key)
            # 拷贝一份
            query_dict = self.request.GET.copy()
            # 可以添加时，数据还在
            query_dict.mutable = True
            # 添加成QueryDict类型继承于dict{name:[value_list]}
            query_dict.setlist(self.name, value_list)
            # 如果有当前页数(把他移除掉，默认显示第一页)
            if 'page' in query_dict:
                query_dict.pop('page')
            # 将值拼成 name=value_list[0]&name=value_list[1]
            param_url = query_dict.urlencode()
            # 判断request.GET传来的参数是否正确且有值
            if param_url:
                url = "{}?{}".format(self.request.path_info, param_url)  # status=1&status=2&status=3&xx=1
            else:
                url = self.request.path_info

            tpl = '<a class="cell" href="{url}"><input type="checkbox" {ck} /><label>{text}</label></a>'
            html = tpl.format(url=url, ck=ck, text=text)
            # 后台传入一个html渲染的标签
            yield mark_safe(html)


class SelectFilter(object):
    def __init__(self, name, data_list, request):
        self.name = name
        self.data_list = data_list
        self.request = request

    def __iter__(self):
        # 生成一个select标签
        yield mark_safe("<select class='select2' multiple='multiple' style='width:100%;' >")
        for item in self.data_list:
            key = str(item[0])
            text = item[1]

            selected = ""
            value_list = self.request.GET.getlist(self.name)

            if key in value_list:
                selected = 'selected'
                value_list.remove(key)
            else:
                value_list.append(key)

            query_dict = self.request.GET.copy()

            query_dict._mutable = True
            query_dict.setlist(self.name, value_list)
            if 'page' in query_dict:
                query_dict.pop('page')

            param_url = query_dict.urlencode()
            if param_url:
                url = "{}?{}".format(self.request.path_info, param_url)  # status=1&status=2&status=3&xx=1
            else:
                url = self.request.path_info
            html = "<option value='{url}' {selected} >{text}</option>".format(url=url, selected=selected, text=text)
            yield mark_safe(html)
        yield mark_safe("</select>")


def issues(request, project_id):
    if request.method == "GET":
        # 根据url做筛选
        allow_filter_name = ['issues_type', 'status', 'priority', 'assign', 'attention']
        condition = {}
        for name in allow_filter_name:
            # 获取参数
            value_list = request.GET.getlist(name)
            # 如果没有参数
            if not value_list:
                continue
            condition["{}__in".format(name)] = value_list
        queryset = models.Issues.objects.filter(project_id=project_id).filter(**condition)
        page_object = Pagination(
            current_page=request.GET.get('page'),
            all_count=queryset.count(),
            base_url=request.path_info,
            query_params=request.GET,
            per_page=10
        )
        form = IssuesModelForm(request)
        # issues_object_list = queryset[page_object.start:page_object.end]
        # context = {
        #     'form': form,
        #     'issues_object_list': issues_object_list,
        #     'page_html': page_object.page_html()
        # }

        # 第二种显示分页方法
        project_total_user = [(request.tracer.project.creator_id, request.tracer.project.creator.username,)]
        join_user = models.ProjectUser.objects.filter(project_id=project_id).values_list('user_id', 'user__username')
        project_total_user.extend(join_user)
        # 获取所有的问题类型
        project_issues_type = models.IssuesType.objects.filter(project_id=project_id).values_list('id', 'title')
        invite_form = InviteModelForm()
        context = page_object.get_page()
        context['invite_form'] = invite_form
        context['issues_object_list'] = queryset[page_object.start:page_object.end]
        context['form'] = form
        context['filter_list'] = [
            {'title': "问题类型", 'filter': CheckFilter('issues_type', project_issues_type, request)},
            {'title': "状态", 'filter': CheckFilter('status', models.Issues.status_choices, request)},
            {'title': "优先级", 'filter': CheckFilter('priority', models.Issues.priority_choices, request)},
            {'title': "指派者", 'filter': SelectFilter('assign', project_total_user, request)},
            {'title': "关注者", 'filter': SelectFilter('attention', project_total_user, request)},
        ]
        return render(request, 'issues.html', context)
    form = IssuesModelForm(request, data=request.POST)
    if form.is_valid():
        form.instance.project = request.tracer.project
        form.instance.creator = request.tracer.user
        form.save()
        return JsonResponse({'status': True})

    return JsonResponse({'status': False, 'error': form.errors})


def issues_detail(request, project_id, issues_id):
    issues_object = models.Issues.objects.filter(id=issues_id, project_id=project_id).first()
    form = IssuesModelForm(request, instance=issues_object)
    return render(request, 'issues_detail.html', {'form': form, 'issues_object': issues_object})


@csrf_exempt
def issues_record(request, project_id, issues_id):
    if request.method == "GET":
        """初始化操作记录"""
        reply_list = models.IssuesReply.objects.filter(issues_id=issues_id, issues__project=request.tracer.project)

        # 将queryset转换为json格式
        data_list = []
        for row in reply_list:
            # 评论用户的所有参数
            data = {
                'id': row.id,
                'reply_type_text': row.get_reply_type_display(),
                'content': row.content,
                'creator': row.creator.username,
                'datetime': row.create_datetime.strftime("%Y-%m-%d %H:%M"),
                'parent_id': row.reply_id,
            }
            data_list.append(data)
        return JsonResponse({'status': True, 'data': data_list})
    form = IssuesReplyModelForm(data=request.POST)

    if form.is_valid():
        form.instance.issues_id = issues_id
        form.instance.reply_type = 2
        form.instance.creator = request.tracer.user
        instance = form.save()
        info = {
            'id': instance.id,
            'reply_type_text': instance.get_reply_type_display(),
            'content': instance.content,
            'creator': instance.creator.username,
            'datetime': instance.create_datetime.strftime("%Y-%m-%d %H:%M"),
            'parent_id': instance.reply_id
        }
        return JsonResponse({'status': True, 'data': info})

    return JsonResponse({'status': False, 'error': form.errors})


@csrf_exempt
def issues_change(request, project_id, issues_id):
    # 获取当前用户的问题信息
    issues_object = models.Issues.objects.filter(id=issues_id, project_id=project_id).first()

    post_dict = json.loads(request.body.decode('utf-8'))
    # 获取到当前更新字段的name属性(方便更改数据库)
    name = post_dict.get('name')
    value = post_dict.get('value')
    # 跳到表结构里
    field_object = models.Issues._meta.get_field(name)

    def create_reply_record(content):
        new_object = models.IssuesReply.objects.create(
            reply_type=1,
            issues=issues_object,
            content=change_record,
            creator=request.tracer.user,
        )
        new_reply_dict = {
            'id': new_object.id,
            'reply_type_text': new_object.get_reply_type_display(),
            'content': new_object.content,
            'creator': new_object.creator.username,
            'datetime': new_object.create_datetime.strftime("%Y-%m-%d %H:%M"),
            'parent_id': new_object.reply_id
        }
        return new_reply_dict

    # 1. 数据库字段更新
    # 1.1 文本
    if name in ["subject", 'desc', 'start_date', 'end_date']:
        if not value:
            if not field_object.null:
                return JsonResponse({'status': False, 'error': "您选择的值不能为空"})
            setattr(issues_object, name, None)
            issues_object.save()
            change_record = "{}更新为空".format(field_object.verbose_name)
        else:
            setattr(issues_object, name, value)
            issues_object.save()
            # 记录：xx更为了value
            change_record = "{}更新为{}".format(field_object.verbose_name, value)

        return JsonResponse({'status': True, 'data': create_reply_record(change_record)})

    # 1.2 FK字段（指派的话要判断是否创建者或参与者）
    if name in ['issues_type', 'module', 'parent', 'assign']:
        # 用户选择为空
        if not value:
            # 不允许为空
            if not field_object.null:
                return JsonResponse({'status': False, 'error': "您选择的值不能为空"})
            # 允许为空
            setattr(issues_object, name, None)
            issues_object.save()
            change_record = "{}更新为空".format(field_object.verbose_name)
        else:  # 用户输入不为空
            if name == 'assign':
                # 是否是项目创建者(因为指派者分为2种)
                if value == str(request.tracer.project.creator_id):
                    # 创建者的对象
                    instance = request.tracer.project.creator
                else:

                    project_user_object = models.ProjectUser.objects.filter(project_id=project_id,
                                                                            user_id=value).first()
                    if project_user_object:
                        # 指派者的对象
                        instance = project_user_object.user
                    else:
                        instance = None
                if not instance:
                    return JsonResponse({'status': False, 'error': "您选择的值不存在"})

                setattr(issues_object, name, instance)
                issues_object.save()
                change_record = "{}更新为{}".format(field_object.verbose_name, str(instance))  # value根据文本获取到内容
            else:
                # 条件判断：用户输入的值，是自己的值(跳到关联表里)
                instance = field_object.remote_field.model.objects.filter(id=value, project_id=project_id).first()

                if not instance:
                    return JsonResponse({'status': False, 'error': "您选择的值不存在"})

                setattr(issues_object, name, instance)
                issues_object.save()
                change_record = "{}更新为{}".format(field_object.verbose_name, str(instance))  # value根据文本获取到内容

        return JsonResponse({'status': True, 'data': create_reply_record(change_record)})

    # 1.3 choices字段
    if name in ['priority', 'status', 'mode']:

        selected_text = None
        for key, text in field_object.choices:
            if str(key) == value:
                selected_text = text
        if not selected_text:
            return JsonResponse({'status': False, 'error': "您选择的值不存在"})

        setattr(issues_object, name, value)
        issues_object.save()
        change_record = "{}更新为{}".format(field_object.verbose_name, selected_text)
        return JsonResponse({'status': True, 'data': create_reply_record(change_record)})

    # 1.4 M2M字段
    if name == "attention":
        # 判断是否为列表类型
        if not isinstance(value, list):
            return JsonResponse({'status': False, 'error': "数据格式错误"})

        if not value:
            issues_object.attention.set(value)
            issues_object.save()
            change_record = "{}更新为空".format(field_object.verbose_name)
        else:
            # values=["1","2,3,4]  ->   id是否是项目成员（参与者、创建者）
            # 获取当前项目的所有成员
            user_dict = {str(request.tracer.project.creator_id): request.tracer.project.creator.username}

            # 判断当前项目是否有参与者(没有就是自己)<拿的是对象>
            project_user_list = models.ProjectUser.objects.filter(project_id=project_id)

            for item in project_user_list:
                # 当前参与或创建项目者的id和名字
                user_dict[str(item.user_id)] = item.user.username
            # 这时候的user_dict是有创建者和参与者的值的(没参与者的话没值)
            username_list = []
            for user_id in value:
                username = user_dict.get(str(user_id))
                if not username:
                    return JsonResponse({'status': False, 'error': "用户不存在请重新设置"})
                username_list.append(username)

            issues_object.attention.set(value)
            issues_object.save()
            change_record = "{}更新为{}".format(field_object.verbose_name, ",".join(username_list))

        return JsonResponse({'status': True, 'data': create_reply_record(change_record)})

    return JsonResponse({'status': False, 'error': "兄弟不要搞我..."})


# 生成邀请连接返回给前端
def invite_url(request, project_id):
    form = InviteModelForm(data=request.POST)
    if form.is_valid():
        """
           1. 创建随机的邀请码
           2. 验证码保存到数据库
           3. 限制：只有创建者才能邀请
       """
        if request.tracer.user != request.tracer.project.creator:
            form.add_error('period', "无权创建邀请码")
            return JsonResponse({'status': False, 'error': form.errors})
        # 获取到随机邀请码
        random_invite_code = uid(request.tracer.user.mobile_phone)
        # 将数据保存(创建者的邀请码和信息)
        form.instance.project = request.tracer.project
        form.instance.code = random_invite_code
        form.instance.creator = request.tracer.user
        form.save()

        # 将验证邀请码返回给前端
        url = "{scheme}://{host}{path}".format(
            scheme=request.scheme,
            host=request.get_host(),
            path=reverse('invite_join', kwargs={'code': random_invite_code}))
        return JsonResponse({'status': True, 'data': url})

    return JsonResponse({'status': False, 'error': form.errors})


def invite_join(request, code):
    # 获取当前时间
    current_datetime = datetime.datetime.now()
    # 判断随机邀请码是否等于当前传来的值(是否存在)
    invite_object = models.ProjectInvite.objects.filter(code=code).first()
    if not invite_object:
        return render(request, 'invite_join.html', {'error': '邀请码不存在'})
    if invite_object.project.creator == request.tracer.user:
        return render(request, 'invite_join.html', {'error': '创建者无需再加入项目'})
    exists = models.ProjectUser.objects.filter(project=request.tracer.project, user=request.tracer.user).exists()
    if exists:
        return render(request, 'invite_join.html', {'error': '已加入项目无需再加入'})
    # 判断是否过期
    max_transaction = models.Transaction.objects.filter(user=invite_object.project.creator, status=2).order_by(
        '-id').first()
    # 如果是免费版
    if max_transaction.price_policy.category == 1:
        # 项目成员数
        max_member = max_transaction.price_policy.project_member
    # 如果是收费版
    else:
        # 判断过期时间是否小于当前时间
        if max_transaction.end_datetime < current_datetime:
            # 如果是的话就变成免费版
            free_object = models.PricePolicy.objects.filter(category=1).first()
            max_member = free_object.project_member
        else:
            # 如果没过期就继续用收费版标准
            max_member = max_transaction.price_policy.project_member

    # 找到目前所有成员(这里包括了创建者)
    current_member = models.ProjectUser.objects.filter(project=invite_object.project).count()

    current_member = current_member + 1

    if current_member >= max_member:
        return render(request, 'invite_join.html', {'error': '项目成员超限，请升级套餐'})

    # 邀请码是否过期(按分钟比较)
    limit_datetime = invite_object.create_datetime + datetime.timedelta(minutes=invite_object.period)

    if current_datetime > limit_datetime:
        return render(request, 'invite_join.html', {'error': '邀请码已过期'})

    # 邀请码数量限制(已邀请的数量是否大于，为空就表示无限)
    if invite_object.count:
        # 已邀请的数量是否大于当前邀请数量
        if invite_object.use_count >= invite_object.count:
            return render(request, 'invite_join.html', {'error': '邀请码数据已使用完'})
        # 邀请成员加1(保存)
        invite_object.use_count += 1
        invite_object.save()
        # 最后再把邀请用户给写入参与项目成员表中
    models.ProjectUser.objects.create(user=request.tracer.user, project=invite_object.project)

    # ####### 问题2： 更新项目参与成员 #######
    invite_object.project.join_count += 1
    invite_object.project.save()

    return render(request, 'invite_join.html', {'project': invite_object.project})
